home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / VideoToolbox 96.06.15 / VideoToolboxSources / Choose.c < prev    next >
Text File  |  1995-10-24  |  6KB  |  184 lines

  1. /*
  2. Choose.c
  3.  
  4. Choose() uses the console to ask the user a multiple choice question and accept
  5. a typed answer. It minimizes the number of keystrokes the user has to type. The
  6. user can select the default answer by just hitting <cr>, or can select any of
  7. the choices by typing just enough characters (typically just one) to make an
  8. unambigious selection. Choose() automatically spells out the rest of the choice.
  9. The user DOES NOT have to terminate the answer with a return. This makes it
  10. feasible to ask the user a long series of multiple-choice questions, since the
  11. user can quickly hit return to obtain default answers and need only type one (or
  12. a few) characters to select non-default choices.
  13.  
  14.     int Choose(int defaultChoice,const char *query,const char *choices[],int n);
  15.  
  16.     choice=Choose(choice,"Will you eat %s?\n",breadFish,2);
  17.  
  18. The first argument and returned value are int, with values in the range 0 to
  19. n-1, where n (the last argument) is the number of possible choices. The
  20. second argument is a format string to be used  (without the optional trailing
  21. \n) in a printf statement. The optional %s will be expanded into a list of
  22. alternatives appropriately punctuated by commas and "or". The third argument is
  23. an array of n string pointers, one string per choice. If the second argument
  24. ends in \n then the printing of that newline character is delayed until AFTER printing
  25. the user's choice.
  26.  
  27. The other routines in this file, MultipleChoice() and YesOrNo() are obsolete,
  28. since Choose() is more convenient, but they are retained for support of old
  29. programs that may use them. Choose is implemented by calling MultipleChoice.
  30.  
  31. MultipleChoice() accepts (and echoes on the console) a partial typed response to
  32. a multiple-choice question, expanding the response to print the full answer that
  33. it uniquely specifies. If alternative answers begin with the same letters (e.g.
  34. "Arabic" and "Armenian") then MultipleChoice keeps accepting characters until an
  35. answer is uniquely determined. Typing any non-printing character (e.g. Return or
  36. Enter) terminates the typed string, e.g. to distinguish "ant" from "anteater".
  37. If the typed string doesn't match any of the supplied answer strings then
  38. MultipleChoice makes the defaultChoice. Thus the user can select the default
  39. answer by just hitting return.
  40.  
  41. YesOrNo() restricts the answers to "Yes" and "No", with a Boolean argument
  42. specifying the default.
  43.  
  44. EXAMPLE:
  45.     static char bread[]="Bread",fish[]="Fish",fowl[]="Fowl";
  46.     static char *breadFishFowl[]={bread,fish,fowl};
  47.     short choice=1;
  48.     
  49.     // new way
  50.     choice=Choose(choice,"Would you like to eat %s?\n",breadFishFowl,3);    
  51.     stillHungry=Choose(stillHungry,"Do you want dessert?\n",noYes,2);
  52.     
  53.     // old way
  54.     printf("Would you like to eat Bread, Fish, or Fowl?");
  55.     choice=MultipleChoice(choice,3,breadFishFowl);
  56.     printf("\n");
  57.     
  58.     // old way
  59.     printf("Do you want dessert?");
  60.     choice=YesOrNo(choice);
  61.     printf("\n");
  62.  
  63. NOTE:
  64. The declarations above explicitly allocate space for the strings "Bread" and "Fish". 
  65. In a stand-alone application you could implicitly allocate that space,
  66.     char *breadFishFowl[]={"Bread","Fish","Fowl"};
  67. but the THINK C compiler doesn't allow this in code resources 
  68. (e.g. a MATLAB MEX file).
  69.  
  70. HISTORY:
  71. 2/16/93    dgp    wrote YesOrNo().
  72. 5/24/93    dgp    added MultipleChoice().
  73. 9/24/93    dgp    cosmetic.
  74. 1/25/94 dgp    enhanced MultipleChoice() to accept characters until they uniquely
  75.             specify an answer, as suggested by Bart Farell.
  76. 7/9/94    dgp added Choose().
  77. 7/13/94    dgp renamed file "Choose.c".
  78. 8/1/94    dgp fixed bug in MultipleChoice(), I was backspacing one too many times.
  79. 9/21/94 dgp added fflush(stdin) to MultipleChoice(), which works better when
  80.             there's no unbuffered input.
  81. 1/5/95 dgp updated to CW5, eliminating the cludges with SIOUXtextWindow.
  82. 6/18/95 dgp changed "abort" to "exit" for better compatibility with CW atexit().
  83. */
  84. #include "VideoToolbox.h"
  85. #if !defined(__TYPES__)
  86.     typedef unsigned char Boolean;
  87. #endif
  88. #define free(ptr) DisposePtr((Ptr)(ptr))
  89. #define malloc(bytes) (void *)NewPtr(bytes)
  90. static char no[]="No",yes[]="Yes";
  91. char *noYes[]={no,yes};
  92.  
  93. int Choose(int defaultChoice,const char *query,char *choices[],int n)
  94. {
  95.     Boolean newline;
  96.     int choice;
  97.     static char *string=NULL;
  98.     char *choiceList;
  99.  
  100.     newline=(query[strlen(query)-1]=='\n');
  101.     choiceList=ChoiceStr(choices,n);
  102.     string=malloc(strlen(query)+strlen(choiceList)+1);
  103.     assert(string!=NULL);
  104. //return defaultChoice=1;
  105.     sprintf(string,query,choiceList);
  106.     if(newline)string[strlen(string)-1]=0;    // strip the trailing newline; print it later.
  107.     BreakLines(string,80);
  108.     printf("%s",string);
  109.     free(string);
  110.     choice=MultipleChoice(defaultChoice,n,choices);
  111.     if(newline)printf("\n");
  112.     return choice;
  113. }
  114.  
  115. Boolean YesOrNo(Boolean defaultChoice)
  116. /* Accept "y" or "n" and spell out "Yes" or "No". Anything else gets defaultChoice. */
  117. {
  118.     return MultipleChoice(defaultChoice,2,noYes);
  119. }
  120.  
  121. int MultipleChoice(short defaultChoice,short nChoices,char *choices[])
  122. {
  123.     char c,s[64];
  124.     short i,j,choice,match,matches,k;
  125.  
  126.     printf(" (%s):",choices[defaultChoice]);
  127.     fflush(stdout);
  128.     for(k=0;k<sizeof(s)-1;k++){
  129.         matches=0;
  130.         do{
  131.             c=getcharUnbuffered();
  132.         }while(c==EOF);
  133.         if(c==14)exit(1);            /* Crude test for command-period. */
  134.         if(!isprint(c))c=0;
  135.         s[k]=c;
  136.         s[k+1]=0;
  137.         for(i=0;i<nChoices;i++){
  138.             match=1;
  139.             for(j=0;j<=k;j++)match&=(tolower(s[j])==tolower(choices[i][j]));
  140.             if(match){
  141.                 choice=i;
  142.                 matches++;
  143.             }
  144.         }
  145.         if(matches<=1 || s[k]==0)break;
  146.         printf("%c",c);
  147.         fflush(stdout);
  148.     }
  149.     fflush(stdin);    // get rid of any unused input
  150.     
  151.     /* Erase partial answer, which could be longer than the default answer. */
  152.     /* -1 because we didn't print the last character typed by the user. */
  153.     k=strlen(s)-1;
  154.     for(j=0;j<k;j++)printf("\b \b");
  155.     
  156.     /* Print answer */
  157.     if(matches==0)choice=defaultChoice;
  158.     printf("%s.",choices[choice]);
  159.     fflush(stdout);
  160.     return choice;
  161. }
  162.  
  163. char *ChoiceStr(char *choices[],int nChoices)
  164. {
  165.     int i,size;
  166.     static char *string=NULL;
  167.     
  168.     size=0;
  169.     for(i=0;i<nChoices;i++)size+=strlen(choices[i])+6;
  170.     string=realloc(string,size);
  171.     assert(string!=NULL);
  172.     string[0]=0;
  173.     for(i=0;i<nChoices;i++){
  174.         sprintf(string,"%s%s",string,choices[i]);
  175.         if(i<nChoices-2)sprintf(string,"%s, ",string);
  176.         if(i==nChoices-2){
  177.             if(nChoices>2)sprintf(string,"%s, or ",string);
  178.             else sprintf(string,"%s or ",string);
  179.         }
  180.         if(i==nChoices-1)sprintf(string,"%s",string);
  181.     }
  182.     return string;
  183. }
  184.